package com.recsmile.rpc.consumer;

import com.recsmile.rpc.annon.RpcService;
import com.recsmile.rpc.bo.RpcThreadPool;
import com.recsmile.rpc.consumer.net.MessageRecvChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created by Administrator on 2016/8/7.
 */
public class ServerStartApplicationContext implements ApplicationContextAware, InitializingBean{

    private String serverAddress;

    private Map<String, Object> serviceMap;

    private static ThreadPoolExecutor executor;

    public static void submit(Runnable runnable){
        if(executor == null){
            synchronized (ServerStartApplicationContext.class){
                if(executor == null){
                    executor = RpcThreadPool.createExecutor(16, -1);
                }
            }
        }
        executor.submit(runnable);
    }

    public ServerStartApplicationContext(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RpcService.class);
        serviceMap = new HashMap<>(beansWithAnnotation.size());
        for(Object o : beansWithAnnotation.values()){
            RpcService rpcService = o.getClass().getAnnotation(RpcService.class);
            if(rpcService != null){
                serviceMap.put(rpcService.value().getName(), o);
            }
        }
    }

    public void afterPropertiesSet() throws Exception {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2);
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss,worker).channel(NioServerSocketChannel.class).childHandler(new MessageRecvChannelInitializer(serviceMap));
            bootstrap.option(ChannelOption.SO_BACKLOG,100).option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true);

            String[] infos = serverAddress.split(":");
            ChannelFuture sync = bootstrap.bind(new InetSocketAddress(infos[0], Integer.parseInt(infos[1]))).sync();
            System.out.print("server start at:"+ serverAddress);
            sync.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }
    }
}
